package com.radar.utils;

import cn.hutool.core.exceptions.UtilException;

@SuppressWarnings("all")
public class BitConverter {

    public static byte[] getBytes(double x) {
        return getBytes(Double.doubleToRawLongBits(x));
    }

    public static byte[] getBytes(double[] data){
        byte[] b = new byte[8 * data.length];
        int index = 0;
        for(int i = 0 ; i < data.length ; i ++){
            getBytes(data[i],b,index);
            index += 8;
        }
        return b;
    }

    public static byte[] getBytes(double[][] data){
        byte[] b = new byte[8 * data.length * data[0].length];
        int index = 0;
        for(int i = 0 ; i < data.length ; i ++){
            for(int j = 0 ; j < data[0].length ; j ++){
                getBytes(data[i][j],b,index);
                index += 8;
            }
        }
        return b;
    }

    public static void getBytes(double x,byte[] b,int index) {
        getBytes(Double.doubleToRawLongBits(x),b,index);
    }

    public static byte[] getBytes(short x) {
        return new byte[] { (byte) x, (byte) (x >>> 8) };
    }

    public static void getBytes(short x,byte[] b,int index) {
        b[index]=(byte) x;
        b[index+1]=(byte) (x >>> 8);
    }

    public static byte[] getBytesInverse(short x) {
        return new byte[] { (byte) (x>>>8), (byte) x };
    }

    public static void getBytesInverse(short x,byte[] b,int index) {
        b[index+1]=(byte) x;
        b[index]=(byte) (x >>> 8);
    }

    public static byte[] getBytes(int x) {
        return new byte[] { (byte) x, (byte) (x >>> 8), (byte) (x >>> 16),
                (byte) (x >>> 24) };
    }

    public static void getBytes(int x,byte[] b,int index) {
        b[index]= (byte) x;
        b[index+1]=(byte) (x >>> 8);
        b[index+2]=(byte) (x >>> 16);
        b[index+3]=(byte) (x >>> 24) ;
    }

    public static byte[] getBytes(long x) {
        return new byte[] { (byte) x, (byte) (x >>> 8),
                (byte) (x >>> 16), (byte) (x >>> 24), (byte) (x >>> 32),
                (byte) (x >>> 40), (byte) (x >>> 48), (byte) (x >>> 56) };
    }

    public static void getBytes(long x,byte[] b,int index) {
        b[index]=(byte) x;
        b[index+1]=(byte) (x >>> 8);
        b[index+2]=(byte) (x >>> 16);
        b[index+3]=(byte) (x >>> 24);
        b[index+4]=(byte) (x >>> 32);
        b[index+5]=(byte) (x >>> 40);
        b[index+6]=(byte) (x >>> 48);
        b[index+7]=(byte) (x >>> 56);
    }

    public static byte[] getBytes(float x) {
        return getBytes(Float.floatToRawIntBits(x));
    }

    public static byte[] getBytes(float[] data){
        byte[] b = new byte[4 * data.length];
        int index = 0;
        for(int i = 0 ; i < data.length ; i ++){
            getBytes(data[i],b,index);
            index += 4;
        }
        return b;
    }

    public static byte[] getBytes(float[][] data){
        byte[] b = new byte[4 * data.length * data[0].length];
        int index = 0;
        for(int i = 0 ; i < data.length ; i ++){
            for(int j = 0 ; j < data[0].length ; j ++){
                getBytes(data[i][j],b,index);
                index += 4;
            }
        }
        return b;
    }

    public static byte[] getBytes(byte[][] data){
        byte[] b = new byte[data.length * data[0].length];
        int index = 0;
        for(int i = 0 ; i < data.length ; i ++){
            for(int j = 0 ; j < data[0].length ; j ++){
                b[index] = data[i][j];
                index ++;
            }
        }
        return b;
    }

    public static void getBytes(float x,byte[] b,int index) {
        getBytes(Float.floatToRawIntBits(x),b,index);
    }

    public static byte[] getBytes(String x) {
        return x.getBytes();
    }

    public boolean toBoolean(byte[] bytes, int index) {
        if (bytes.length != 1)
            throw new UtilException(
                    "The length of the byte array must be at least 1 byte long.");
        return bytes[index] != 0;
    }

    public static double toDouble(byte[] bytes, int index) {
        if (bytes.length - index < 8) {
            throw new UtilException(
                    "The length of the byte array must be at least 8 bytes long.");
        }
        return Double.longBitsToDouble(toInt64(bytes, index));
    }

    public static double[][] toDouble(byte[] bytes,int xnum , int ynum) {
        if (bytes.length != ynum * xnum * 8)
            throw new UtilException(
                    "The length of the byte array must be > xnum * ynum * 8");
        double[][] data = new double[ynum][xnum];
        int index = 0;
        for(int i = 0 ; i < data.length ; i ++){
            for(int j = 0 ; j < data[0].length ; j ++){
                data[i][j] = toDouble(bytes,index);
                index += 8;
            }
        }
        return data;
    }

    public static short toInt16(byte[] bytes, int index)  {
        if (bytes.length - index < 2) {
            throw new UtilException(
                    "The length of the byte array must be at least 2 bytes long.");
        }
        return (short) ((0xff & bytes[index]) << 0 | (0xff & bytes[index + 1]) << 8);
    }

    public static short toInt16Inverse(byte[] bytes, int index)  {
        if (bytes.length - index < 2)
            throw new UtilException(
                    "The length of the byte array must be at least 4 bytes long.");

        return (short) ((0xff & bytes[index+1]) << 0 | (0xff & bytes[index ]) << 8);
    }

    public static int toInt32(byte[] bytes, int index)  {
        if (bytes.length - index < 4)
            throw new UtilException(
                    "The length of the byte array must be at least 4 bytes long.");

        return ((0xff & bytes[index+3]) << 56
                | (0xff & bytes[index + 2]) << 48
                | (0xff & bytes[index + 1]) << 40 |
                (0xff & bytes[index ]) << 32);
    }

    public static int toInt32Inverse(byte[] bytes, int index)  {
        if (bytes.length - index < 4)
            throw new UtilException(
                    "The length of the byte array must be at least 4 bytes long.");

        return  ( (0xff & bytes[index]) << 56
                |  (0xff & bytes[index + 1]) << 48
                |  (0xff & bytes[index + 2]) << 40 |
                 (0xff & bytes[index + 3]) << 32);
    }

    public static long toInt64(byte[] bytes, int index)  {
        if (bytes.length - index < 8)
            throw new UtilException(
                    "The length of the byte array must be at least 8 bytes long.");
        return  ((long) (0xff & bytes[index+7]) << 56
                | (long) (0xff & bytes[index + 6]) << 48
                | (long) (0xff & bytes[index + 5]) << 40
                | (long) (0xff & bytes[index + 4]) << 32
                | (long) (0xff & bytes[index + 3]) << 24
                | (long) (0xff & bytes[index + 2]) << 16
                | (long) (0xff & bytes[index + 1]) << 8 |
                (long) (0xff & bytes[index]) );
    }

    public static float toSingle(byte[] bytes, int index)  {
        if (bytes.length - index < 4)
            throw new UtilException(
                    "The length of the byte array must be at least 4 bytes long.");
        return Float.intBitsToFloat(toInt32(bytes, index));
    }

    public static String toString(byte[] bytes)  {
        if (bytes == null)
            throw new UtilException("The byte array must have at least 1 byte.");
        return new String(bytes);
    }
}
